<?php

declare(strict_types=1);

namespace App\Services;

use App\Helpers\Password;
use App\Repositories\AuthRepository;
use App\Repositories\RoleRepository;
use App\Validations\AuthValidation;
use App\Validations\UserValidation;
use InvalidArgumentException;

class AuthService extends BaseService
{
    /**
     * Obtiene una instancia del repositorio de los roles.
     */
    private function roleRepository(): RoleRepository
    {
        return new RoleRepository;
    }

    /**
     * Obtiene una instancia del servicio de los usuarios.
     */
    private function userService(): UserService
    {
        return new UserService($this->app());
    }

    /**
     * Obtiene una instancia de las reglas de validación de autenticación.
     */
    private function authValidation(): AuthValidation
    {
        return new AuthValidation;
    }

    /**
     * Obtiene una instancia de las reglas de validación de los usuarios.
     */
    private function userValidation(): UserValidation
    {
        return new UserValidation;
    }

    /**
     * Obtiene una instancia del repositorio de los usuarios.
     */
    private function authRepository(): AuthRepository
    {
        return new AuthRepository;
    }

    /**
     * Registra la información de un nuevo usuario.
     */
    public function register(array $data): string
    {
        $data['role_id'] = $this->roleRepository()->findIdByColumn('name', 'user');

        return $this->userService()->register($data);
    }

    /**
     * Obtiene la información de sesión de un usuario.
     */
    public function getSession(array $data): string
    {
        $fields = array_keys($data);
        unset($fields[array_search('nickname', $fields)]);

        $is_email = $this->gump()->is_valid($data, $this->authValidation()->getRules('nickname', true));

        // Define el modo de autenticación.
        $identifyBy = $is_email === true ? 'email' : 'username';
        $fields[] = $identifyBy;

        $userValidation = $this->userValidation();

        // Obtiene las reglas de validación.
        $rules = $userValidation->getRules($fields, true);

        $rules['nickname'] = $rules[$identifyBy];
        unset($rules[$identifyBy]);

        // Valida la información de autenticación.
        $this->gump()->validation_rules($rules);
        $this->gump()->filter_rules($userValidation->getFilters($fields));

        $data = $this->gump()->run($data);

        // Comprueba si existen errores de validación.
        if ($this->gump()->errors()) {
            throw new InvalidArgumentException('La información de autenticación es incorrecta');
        }

        // Consulta la información de acceso del usuario.
        $user = $this->authRepository()->findCredentialsByColumn($identifyBy, $data['nickname']);

        // Comprueba la información de acceso del usuario.
        if (empty($user) || ! Password::verify($data['password'], $user['password'])) {
            throw new InvalidArgumentException('Las credenciales de acceso son incorrectas');
        }

        // Comprueba el estatus de actividad del usuario.
        if (empty($user['is_active'])) {
            throw new InvalidArgumentException('El usuario que intenta autenticarse no está activo');
        }

        return $user['id'];
    }
}
